#include "RngLib.h"
#include<stdlib.h>
#include<string.h>
#include<memory.h>


#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif

char * bcopy(const char *src, char *dest, int count)
{
  char *tmp = dest;
  while(count--)
    *tmp++ = *src++;
  return dest;
}
/*******************************************************************************
*
* rngCreate - create an empty ring buffer
*
* This routine creates a ring buffer of size <nbytes>, and initializes
* it.  Memory for the buffer is allocated from the system memory partition.
*
* RETURNS
* The ID of the ring buffer, or NULL if memory cannot be allocated.
*/

RING_ID   rngCreate(
        int nbytes  )
{
    char *buffer;
    RING_ID rngBuf = (RING_ID) malloc(sizeof (rng));

    if (rngBuf == 0)
        return 0;

    /* bump number of bytes requested because ring buffer algorithm
    * always leaves at least one empty byte in buffer */

    buffer = (char *) malloc((unsigned) ++nbytes);

    if (buffer == 0)
    {
        free  ((char *)rngBuf);
        return 0;
    }

    rngBuf->bufSize = nbytes;
    rngBuf->buf	    = buffer;

    rngFlush (rngBuf);

    return rngBuf;
}


/*******************************************************************************
*
* rngFlush - make a ring buffer empty
*
* This routine initializes a specified ring buffer to be empty.
* Any data currently in the buffer will be lost.
*
* RETURNS: N/A
*/

void rngFlush(RING_ID rngBuf)
{
    rngBuf->pToBuf   = 0;
    rngBuf->pFromBuf = 0;
}


/*******************************************************************************
*
* rngDelete - delete a ring buffer
*
* This routine deletes a specified ring buffer.
* Any data currently in the buffer will be lost.
*
* RETURNS: N/A
*/

void rngDelete(RING_ID rngBuf)
{
    if(rngBuf)
    {
        free  (rngBuf->buf);
        free ((char *)rngBuf);
        rngBuf = 0;
    }
}


/*******************************************************************************
*
* rngBufGet - get characters from a ring buffer
*
* This routine copies bytes from the ring buffer <rngId> into <buffer>.
* It copies as many bytes as are available in the ring, up to <maxbytes>.
* The bytes copied will be removed from the ring.
*
* RETURNS:
* The number of bytes actually received from the ring buffer;
* it may be zero if the ring buffer is empty at the time of the call.
*/

int  rngBufGet(RING_ID rngBuf,
    char *buffer,               /* pointer to buffer to receive data */
    int maxbytes                /* maximum number of bytes to get    */
    )
{
    int bytesgot = 0;
    int pToBuf = rngBuf->pToBuf;
    int bytes2;
    int pRngTmp = 0;

    if (pToBuf >= rngBuf->pFromBuf)
    {
        /* pToBuf has not wrapped around */

        bytesgot = min (maxbytes, pToBuf - rngBuf->pFromBuf);
        bcopy (&rngBuf->buf [rngBuf->pFromBuf], buffer, bytesgot);
        rngBuf->pFromBuf += bytesgot;
    }
    else
    {
        /* pToBuf has wrapped around.  Grab chars up to the end of the
        * buffer, then wrap around if we need to. */

        bytesgot = min (maxbytes, rngBuf->bufSize - rngBuf->pFromBuf);
        bcopy (&rngBuf->buf [rngBuf->pFromBuf], buffer, bytesgot);
        pRngTmp = rngBuf->pFromBuf + bytesgot;

        /* If pFromBuf is equal to bufSize, we've read the entire buffer,
        * and need to wrap now.  If bytesgot < maxbytes, copy some more chars
        * in now. */

        if (pRngTmp == rngBuf->bufSize)
        {
            bytes2 = min (maxbytes - bytesgot, pToBuf);
            bcopy (rngBuf->buf, buffer + bytesgot, bytes2);
            rngBuf->pFromBuf = bytes2;
            bytesgot += bytes2;
        }
        else
            rngBuf->pFromBuf = pRngTmp;
    }
    return (bytesgot);
}


/*******************************************************************************
*
* rngBufPut - put bytes into a ring buffer
*
* This routine puts bytes from <buffer> into ring buffer <ringId>.  The
* specified number of bytes will be put into the ring, up to the number of
* bytes available in the ring.
*
* INTERNAL
* Always leaves at least one byte empty between pToBuf and pFromBuf, to
* eliminate ambiguities which could otherwise occur when the two pointers
* are equal.
*
* RETURNS:
* The number of bytes actually put into the ring buffer;
* it may be less than number requested, even zero,
* if there is insufficient room in the ring buffer at the time of the call.
*/

int rngBufPut
( 
    RING_ID rngBuf,              /* ring buffer to put data into  */
 char *buffer,               /* buffer to get data from       */
 int nbytes                   /* number of bytes to try to put */
 )
{
    int bytesput = 0;
    int pFromBuf = rngBuf->pFromBuf;
    int bytes2;
    int pRngTmp = 0;

    if (pFromBuf > rngBuf->pToBuf)
    {
        /* pFromBuf is ahead of pToBuf.  We can fill up to two bytes
        * before it */

        bytesput = min (nbytes, pFromBuf - rngBuf->pToBuf - 1);
        bcopy (buffer, &rngBuf->buf [rngBuf->pToBuf], bytesput);
        rngBuf->pToBuf += bytesput;
    }
    else if (pFromBuf == 0)
    {
        /* pFromBuf is at the beginning of the buffer.  We can fill till
        * the next-to-last element */

        bytesput = min (nbytes, rngBuf->bufSize - rngBuf->pToBuf - 1);
        bcopy (buffer, &rngBuf->buf [rngBuf->pToBuf], bytesput);
        rngBuf->pToBuf += bytesput;
    }
    else
    {
        /* pFromBuf has wrapped around, and its not 0, so we can fill
        * at least to the end of the ring buffer.  Do so, then see if
        * we need to wrap and put more at the beginning of the buffer. */

        bytesput = min (nbytes, rngBuf->bufSize - rngBuf->pToBuf);
        bcopy (buffer, &rngBuf->buf [rngBuf->pToBuf], bytesput);
        pRngTmp = rngBuf->pToBuf + bytesput;

        if (pRngTmp == rngBuf->bufSize)
        {
            /* We need to wrap, and perhaps put some more chars */

            bytes2 = min (nbytes - bytesput, pFromBuf - 1);
            bcopy (buffer + bytesput, rngBuf->buf, bytes2);
            rngBuf->pToBuf = bytes2;
            bytesput += bytes2;
        }
        else
            rngBuf->pToBuf = pRngTmp;
    }
    return (bytesput);
}



/*******************************************************************************
*
* rngIsEmpty - test if a ring buffer is empty
*
* This routine determines if a specified ring buffer is empty.
*
* RETURNS:
* TRUE if empty, FALSE if not.
*/
int rngIsEmpty
(RING_ID rngBuf
 )
{
    return (rngBuf->pToBuf == rngBuf->pFromBuf);
}




/*******************************************************************************
*
* rngIsFull - test if a ring buffer is full (no more room)
*
* This routine determines if a specified ring buffer is completely full.
*
* RETURNS:
* TRUE if full, FALSE if not.
*/

int rngIsFull
(RING_ID rngBuf
 )
{
    int n = rngBuf->pToBuf - rngBuf->pFromBuf + 1;

    return ((n == 0) || (n == rngBuf->bufSize));
}



/*******************************************************************************
*
* rngNBytes - determine the number of bytes in a ring buffer
*
* This routine determines the number of bytes currently in a specified
* ring buffer.
*
* RETURNS: The number of bytes filled in the ring buffer.
*/

int rngNBytes
(RING_ID rngBuf )
{
    int n = rngBuf->pToBuf - rngBuf->pFromBuf;

    if (n < 0)
        n += rngBuf->bufSize;

    return (n);
}



/*******************************************************************************
*
* rngPutAhead - put a byte ahead in a ring buffer without moving ring pointers
*
* This routine writes a byte into the ring, but does not move the ring buffer
* pointers.  Thus the byte will not yet be available to rngBufGet() calls.
* The byte is written <offset> bytes ahead of the next input location in the
* ring.  Thus, an offset of 0 puts the byte in the same position as would
* RNG_ELEM_PUT would put a byte, except that the input pointer is not updated.
*
* Bytes written ahead in the ring buffer with this routine can be made available
* all at once by subsequently moving the ring buffer pointers with the routine
* rngMoveAhead().
*
* Before calling rngPutAhead(), the caller must verify that at least
* <offset> + 1 bytes are available in the ring buffer.
*
* RETURNS: N/A
*/

void  rngPutAhead
(
    RING_ID rngBuf,
    char byte,             /* byte to be put in ring        */
 int offset             /* offset beyond next input byte where to put byte */
 )
{
    int n = rngBuf->pToBuf + offset;

    if (n >= rngBuf->bufSize)
        n -= rngBuf->bufSize;

    *(rngBuf->buf + n) = byte;
}


/*******************************************************************************
*
* rngMoveAhead - advance a ring pointer by <n> bytes
*
* This routine advances the ring buffer input pointer by <n> bytes.  This makes
* <n> bytes available in the ring buffer, after having been written ahead in
* the ring buffer with rngPutAhead().
*
* RETURNS: N/A
*/

void rngMoveAhead
(
    RING_ID rngBuf,
 int n            /* number of bytes ahead to move input pointer */
 )
{
    n += rngBuf->pToBuf;

    if (n >= rngBuf->bufSize)
        n -= rngBuf->bufSize;

    rngBuf->pToBuf = n;
}



int rngBufGetNoDel (RING_ID rngBuf,char *buffer, int maxbytes)
{
    int retval;
    int temp=rngBuf->pFromBuf;
    retval=rngBufGet(rngBuf,buffer,  maxbytes);
    rngBuf->pFromBuf=temp;
    return retval;

}

void rngMoveRead
(
    RING_ID rngBuf,
 int n            /* number of bytes ahead to move input pointer */
 )
{
    n += rngBuf->pFromBuf;

    if (n >= rngBuf->bufSize)
        n -= rngBuf->bufSize;

    rngBuf->pFromBuf = n;
}

/*******************************************************************************
*
* rngFindPattern - 在环形缓冲区中查找二进制模式
*
* 在环形缓冲区中查找指定的二进制模式
*
* RETURNS:
* 找到模式的位置，如果没找到返回-1
*/
int rngFindPattern(RING_ID rngBuf, const char *pattern, int patternLen)
{
    int nBytes = rngNBytes(rngBuf);
    if (nBytes < patternLen) return -1;
    
    int searchLen = nBytes - patternLen + 1;
    char *tempBuffer = (char *)malloc(nBytes);
    if (!tempBuffer) return -1;
    
    // 从环形缓冲区中读取所有数据到临时缓冲区
    int bytesRead = rngBufGetNoDel(rngBuf, tempBuffer, nBytes);
    if (bytesRead != nBytes) {
        free(tempBuffer);
        return -1;
    }
    
    // 在临时缓冲区中查找模式
    for (int i = 0; i < searchLen; i++) {
        if (memcmp(tempBuffer + i, pattern, patternLen) == 0) {
            free(tempBuffer);
            return i;
        }
    }
    
    free(tempBuffer);
    return -1;
}

/*******************************************************************************
*
* rngFindTextPattern - 在环形缓冲区中查找文本模式
*
* 在环形缓冲区中查找指定的文本模式
*
* RETURNS:
* 找到模式的位置，如果没找到返回-1
*/
int rngFindTextPattern(RING_ID rngBuf, const char *pattern)
{
    int patternLen = strlen(pattern);
    return rngFindPattern(rngBuf, pattern, patternLen);
}

/*******************************************************************************
*
* rngGetDataFromPos - 从指定位置获取数据
*
* 从环形缓冲区的指定位置开始获取指定数量的字节
*
* RETURNS:
* 实际读取的字节数
*/
int rngGetDataFromPos(RING_ID rngBuf, char *buffer, int startPos, int maxBytes)
{
    int nBytes = rngNBytes(rngBuf);
    if (startPos >= nBytes || maxBytes <= 0) return 0;
    
    int actualBytes = (startPos + maxBytes > nBytes) ? (nBytes - startPos) : maxBytes;
    
    // 临时移动读取指针到指定位置
    int originalPos = rngBuf->pFromBuf;
    rngMoveRead(rngBuf, startPos);
    
    // 读取数据
    int bytesRead = rngBufGetNoDel(rngBuf, buffer, actualBytes);
    
    // 恢复原始读取指针位置
    rngBuf->pFromBuf = originalPos;
    
    return bytesRead;
}

/*******************************************************************************
*
* rngRemoveDataUpTo - 移除指定数量的数据
*
* 从环形缓冲区中移除指定数量的字节
*
* RETURNS: N/A
*/
void rngRemoveDataUpTo(RING_ID rngBuf, int nBytes)
{
    if (nBytes <= 0) return;
    
    int availableBytes = rngNBytes(rngBuf);
    if (nBytes > availableBytes) {
        nBytes = availableBytes;
    }
    
    rngMoveRead(rngBuf, nBytes);
}
